-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(tests): resolve linting issues in test files #1210
fix(tests): resolve linting issues in test files #1210
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
🚀 Code Review Initiated The review process for this pull request has started. Our system is analyzing the changes for:
You will receive structured and actionable feedback shortly! ⏳ |
🤖 Devin AI EngineerI'll be helping with this pull request! Here's what you should know: ✅ I will automatically:
⚙️ Control Options:
|
This comment was generated by github-actions[bot]! JS SDK Coverage Report📊 Coverage report for JS SDK can be found at the following URL: 📁 Test report folder can be found at the following URL: |
I've reviewed the test coverage additions for the base toolset. Overall, the test coverage is comprehensive and well-structured. Here's my assessment: Strengths 👍
Areas for Improvement 🔧
// Suggested structure:
- core/
- constructor.spec.ts
- actions.spec.ts
- entities.spec.ts
- security/
- authentication.spec.ts
- permissions.spec.ts
- processors/
- chain.spec.ts
- validation.spec.ts
const createTestAction = async (toolset, name, callback) => {
return await toolset.createAction({
actionName: name,
callback
});
};
const TEST_CONSTANTS = {
API_KEY: testConfig.COMPOSIO_API_KEY,
BASE_URL: testConfig.BACKEND_HERMES_URL,
DEFAULT_ENTITY: "default"
};
/**
* Tests for ComposioToolSet constructor functionality
* Verifies initialization, configuration and error handling
*/
describe('constructor', () => { Potential Issues
|
await toolset.createAction({ | ||
actionName, | ||
callback: async () => { | ||
executionCount++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider using atomic operations or a mutex here to prevent race conditions in concurrent tests. The current implementation could lead to flaky tests.
|
||
it("should handle rate limiting", async () => { | ||
// Simulate rate limiting by making multiple rapid requests | ||
const promises = Array(10).fill(null).map(() => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The rate limiting test could be flaky due to timing issues. Consider adding configurable delays or retry logic:
const executeWithRetry = async (action, maxRetries = 3, delay = 1000) => {
for (let i = 0; i < maxRetries; i++) {
try {
return await toolset.executeAction(action);
} catch (e) {
if (i === maxRetries - 1) throw e;
await new Promise(resolve => setTimeout(resolve, delay));
}
}
};
|
||
it("should handle large response payloads", async () => { | ||
const actionName = "large_response_action"; | ||
const largeData = Array(1000).fill({ key: "value" }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider parameterizing the payload size for different test environments. This would make the test more flexible and prevent potential memory issues:
const TEST_CONFIG = {
smallPayload: 100,
mediumPayload: 1000,
largePayload: 10000,
};
const size = process.env.TEST_PAYLOAD_SIZE || TEST_CONFIG.mediumPayload;
const largeData = Array(size).fill({ key: "value" });
}); | ||
}); | ||
|
||
describe('Security and Edge Cases', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider adding JSDoc comments to describe the test suite and its purpose:
/**
* Security and Edge Cases Test Suite
* Tests various security aspects and edge cases of the ComposioToolSet:
* - Rate limiting behavior
* - Authentication failures
* - Permission handling
* - Large payload processing
* - Concurrent execution
* - Input sanitization
* - Output validation
*/
describe('Security and Edge Cases', () => {
}; | ||
} | ||
} | ||
} | ||
|
||
describe("ComposioToolSet class tests", () => { | ||
let toolset: ComposioToolSet; | ||
const testConfig = getTestConfig(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider extracting test constants to improve maintainability:
const TEST_CONSTANTS = {
API: {
KEY: testConfig.COMPOSIO_API_KEY,
BASE_URL: testConfig.BACKEND_HERMES_URL,
},
RUNTIME: {
DEFAULT: "composio-ai",
CUSTOM: "custom-runtime"
},
ENTITY: {
DEFAULT: "default",
CUSTOM: "custom-entity",
RESTRICTED: "restricted-entity"
}
};
6341bb2
to
bce5986
Compare
it("should handle rate limiting", async () => { | ||
// Simulate rate limiting by making multiple rapid requests | ||
const promises = Array(10).fill(null).map(() => | ||
toolset.executeAction({ | ||
action: "github_issues_create", | ||
params: { title: "Test Issue" }, | ||
entityId: "default", | ||
}) | ||
); | ||
|
||
await expect(Promise.all(promises)).rejects.toThrow(); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rate limiting test doesn't verify the specific rate limit error, should check for 429 status code.
📝 Committable Code Suggestion
‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.
it("should handle rate limiting", async () => { | |
// Simulate rate limiting by making multiple rapid requests | |
const promises = Array(10).fill(null).map(() => | |
toolset.executeAction({ | |
action: "github_issues_create", | |
params: { title: "Test Issue" }, | |
entityId: "default", | |
}) | |
); | |
await expect(Promise.all(promises)).rejects.toThrow(); | |
}); | |
it("should handle rate limiting", async () => { | |
const promises = Array(10).fill(null).map(() => | |
toolset.executeAction({ | |
action: "github_issues_create", | |
params: { title: "Test Issue" }, | |
entityId: "default", | |
}) | |
); | |
await expect(Promise.all(promises)).rejects.toMatchObject({ | |
status: 429 | |
}); | |
}); |
it("should sanitize input parameters", async () => { | ||
const actionName = "input_sanitization_test"; | ||
await toolset.createAction({ | ||
actionName, | ||
inputParams: z.object({ | ||
text: z.string(), | ||
}), | ||
callback: async (params) => ({ | ||
data: { sanitized: params.text }, | ||
successful: true, | ||
}), | ||
}); | ||
|
||
// Test with potentially malicious input | ||
const maliciousInput = "<script>alert('xss')</script>"; | ||
const result = await toolset.executeAction({ | ||
action: actionName, | ||
params: { text: maliciousInput }, | ||
entityId: "default", | ||
}); | ||
|
||
expect(result.data.sanitized).not.toContain("<script>"); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sanitization test only checks script tags, should test multiple injection patterns.
📝 Committable Code Suggestion
‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.
it("should sanitize input parameters", async () => { | |
const actionName = "input_sanitization_test"; | |
await toolset.createAction({ | |
actionName, | |
inputParams: z.object({ | |
text: z.string(), | |
}), | |
callback: async (params) => ({ | |
data: { sanitized: params.text }, | |
successful: true, | |
}), | |
}); | |
// Test with potentially malicious input | |
const maliciousInput = "<script>alert('xss')</script>"; | |
const result = await toolset.executeAction({ | |
action: actionName, | |
params: { text: maliciousInput }, | |
entityId: "default", | |
}); | |
expect(result.data.sanitized).not.toContain("<script>"); | |
}); | |
it("should sanitize input parameters", async () => { | |
const maliciousInputs = [ | |
"<script>alert('xss')</script>", | |
"<img src='x' onerror='alert(1)'>", | |
"javascript:alert(1)", | |
"<svg onload='alert(1)'>", | |
"<iframe src='javascript:alert(1)'>" | |
]; | |
for (const input of maliciousInputs) { | |
const result = await toolset.executeAction({ | |
action: actionName, | |
params: { text: input }, | |
entityId: "default", | |
}); | |
expect(result.data.sanitized).not.toContain(input); | |
expect(result.data.sanitized).not.toMatch(/<[^>]*script|javascript:|on\w+=/i); | |
} | |
}); |
it("should handle concurrent execution", async () => { | ||
const actionName = "concurrent_action"; | ||
let executionCount = 0; | ||
|
||
await toolset.createAction({ | ||
actionName, | ||
callback: async () => { | ||
executionCount++; | ||
return { data: { count: executionCount }, successful: true }; | ||
}, | ||
}); | ||
|
||
const promises = Array(5).fill(null).map(() => | ||
toolset.executeAction({ | ||
action: actionName, | ||
params: {}, | ||
entityId: "default", | ||
}) | ||
); | ||
|
||
const results = await Promise.all(promises); | ||
expect(results).toHaveLength(5); | ||
expect(executionCount).toBe(5); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concurrent execution test has race condition, should use atomic operations or separate counters.
📝 Committable Code Suggestion
‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.
it("should handle concurrent execution", async () => { | |
const actionName = "concurrent_action"; | |
let executionCount = 0; | |
await toolset.createAction({ | |
actionName, | |
callback: async () => { | |
executionCount++; | |
return { data: { count: executionCount }, successful: true }; | |
}, | |
}); | |
const promises = Array(5).fill(null).map(() => | |
toolset.executeAction({ | |
action: actionName, | |
params: {}, | |
entityId: "default", | |
}) | |
); | |
const results = await Promise.all(promises); | |
expect(results).toHaveLength(5); | |
expect(executionCount).toBe(5); | |
}); | |
const executionCount = new Atomic(0); | |
await toolset.createAction({ | |
actionName, | |
callback: async () => { | |
const count = executionCount.incrementAndGet(); | |
return { data: { count }, successful: true }; | |
}, | |
}); |
- Add security and edge case tests - Add integration tests for processor chains - Add input/output validation tests - Add concurrent execution tests - Add rate limiting tests - Add large payload tests Co-Authored-By: [email protected] <[email protected]>
bce5986
to
ebdc8c4
Compare
const promises = Array(10).fill(null).map(() => | ||
toolset.executeAction({ | ||
action: "github_issues_create", | ||
params: { title: "Test Issue" }, | ||
entityId: "default", | ||
}) | ||
); | ||
|
||
await expect(Promise.all(promises)).rejects.toThrow(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test case for rate limiting is flawed; it assumes rate limiting will always trigger with 10 requests, which is implementation dependent and could be flaky. Use mock/stub instead.
📝 Committable Code Suggestion
‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.
const promises = Array(10).fill(null).map(() => | |
toolset.executeAction({ | |
action: "github_issues_create", | |
params: { title: "Test Issue" }, | |
entityId: "default", | |
}) | |
); | |
await expect(Promise.all(promises)).rejects.toThrow(); | |
const rateLimiter = jest.spyOn(toolset, 'executeAction'); | |
rateLimiter.mockRejectedValueOnce(new Error('Rate limit exceeded')); | |
await expect(toolset.executeAction({ | |
action: "github_issues_create", | |
params: { title: "Test Issue" }, | |
entityId: "default", | |
})).rejects.toThrow('Rate limit exceeded'); | |
rateLimiter.mockRestore(); |
const maliciousInput = "<script>alert('xss')</script>"; | ||
const result = await toolset.executeAction({ | ||
action: actionName, | ||
params: { text: maliciousInput }, | ||
entityId: "default", | ||
}); | ||
|
||
expect(result.data.sanitized).not.toContain("<script>"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The sanitization test is incomplete; it checks if <script> is removed but doesn't verify other XSS vectors or ensure the sanitization is secure. Test multiple attack vectors.
📝 Committable Code Suggestion
‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.
const maliciousInput = "<script>alert('xss')</script>"; | |
const result = await toolset.executeAction({ | |
action: actionName, | |
params: { text: maliciousInput }, | |
entityId: "default", | |
}); | |
expect(result.data.sanitized).not.toContain("<script>"); | |
const maliciousInputs = [ | |
"<script>alert('xss')</script>", | |
"<img src='x' onerror='alert(1)'>", | |
"javascript:alert(1)", | |
"<svg/onload=alert(1)>", | |
"<iframe src='javascript:alert(1)'>" | |
]; | |
for (const input of maliciousInputs) { | |
const result = await toolset.executeAction({ | |
action: actionName, | |
params: { text: input }, | |
entityId: "default", | |
}); | |
expect(result.data.sanitized).not.toContain("<script>"); | |
expect(result.data.sanitized).not.toMatch(/javascript:/i); | |
expect(result.data.sanitized).not.toMatch(/on\w+\s*=/i); | |
expect(result.data.sanitized).not.toMatch(/<iframe[^>]*>/i); | |
} |
it("should handle concurrent execution", async () => { | ||
const actionName = "concurrent_action"; | ||
let executionCount = 0; | ||
|
||
await toolset.createAction({ | ||
actionName, | ||
callback: async () => { | ||
executionCount++; | ||
return { data: { count: executionCount }, successful: true }; | ||
}, | ||
}); | ||
|
||
const promises = Array(5).fill(null).map(() => | ||
toolset.executeAction({ | ||
action: actionName, | ||
params: {}, | ||
entityId: "default", | ||
}) | ||
); | ||
|
||
const results = await Promise.all(promises); | ||
expect(results).toHaveLength(5); | ||
expect(executionCount).toBe(5); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The concurrent execution test has a race condition; it relies on a shared counter that could lead to flaky tests. Use atomic operations or a different verification approach.
📝 Committable Code Suggestion
‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.
it("should handle concurrent execution", async () => { | |
const actionName = "concurrent_action"; | |
let executionCount = 0; | |
await toolset.createAction({ | |
actionName, | |
callback: async () => { | |
executionCount++; | |
return { data: { count: executionCount }, successful: true }; | |
}, | |
}); | |
const promises = Array(5).fill(null).map(() => | |
toolset.executeAction({ | |
action: actionName, | |
params: {}, | |
entityId: "default", | |
}) | |
); | |
const results = await Promise.all(promises); | |
expect(results).toHaveLength(5); | |
expect(executionCount).toBe(5); | |
}); | |
const atomicCounter = new Int32Array(new SharedArrayBuffer(4)); | |
await toolset.createAction({ | |
actionName, | |
callback: async () => { | |
Atomics.add(atomicCounter, 0, 1); | |
return { data: { count: AtomicCounter.load(atomicCounter, 0) }, successful: true }; | |
}, | |
}); | |
const promises = Array(5).fill(null).map(() => | |
toolset.executeAction({ | |
action: actionName, | |
params: {}, | |
entityId: "default", | |
}) | |
); | |
const results = await Promise.all(promises); | |
expect(results).toHaveLength(5); | |
expect(Atomics.load(atomicCounter, 0)).toBe(5); |
let toolset: ComposioToolSet; | ||
const testConfig = getTestConfig(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing import for getTestConfig causes runtime errors. Import or define the function.
📝 Committable Code Suggestion
‼️ Ensure you review the code suggestion before committing it to the branch. Make sure it replaces the highlighted code, contains no missing lines, and has no issues with indentation.
let toolset: ComposioToolSet; | |
const testConfig = getTestConfig(); | |
import { getTestConfig } from './config'; | |
let toolset: ComposioToolSet; | |
const testConfig = getTestConfig(); |
Co-Authored-By: [email protected] <[email protected]>
Devin is currently unreachable - the session may have died. |
Closing due to inactivity. |
Comprehensive test suite for ComposioToolSet
Link to Devin run: https://app.devin.ai/sessions/2142c6b5bc4d40a4ad9c4248531541d4